package cc.shacocloud.mirage.core;

import cc.shacocloud.mirage.bean.bind.Component;
import cc.shacocloud.mirage.bean.exception.NoSuchBeanException;
import io.vertx.core.Promise;
import io.vertx.core.Verticle;
import io.vertx.core.spi.VerticleFactory;
import lombok.Setter;

import java.util.Objects;
import java.util.concurrent.Callable;

/**
 * 一个由 {@link ApplicationContext} 支持的{@link VerticleFactory} 实现
 */
@Component
public class ApplicationContextVerticleFactoryImpl implements ApplicationContextVerticleFactory {
    
    @Setter
    private ApplicationContext applicationContext;
    
    @Override
    public String prefix() {
        return applicationContext.getApplicationName();
    }
    
    @Override
    public void createVerticle(String verticleName, ClassLoader classLoader, Promise<Callable<Verticle>> promise) {
        try {
            final String verticleBeanName = VerticleFactory.removePrefix(verticleName);
            
            Callable<Verticle> verticleCallable = null;
            
            // 优先以bean名称检查
            if (applicationContext.containsBean(verticleBeanName)) {
                verticleCallable = () -> (Verticle) applicationContext.getBean(verticleBeanName);
            }
            
            // 其次使用bean类型
            if (Objects.isNull(verticleCallable)) {
                try {
                    Class<?> clazz = Class.forName(verticleBeanName);
                    if (applicationContext.containsBean(clazz)) {
                        Verticle verticle = (Verticle) applicationContext.getBean(clazz);
                        verticleCallable = () -> verticle;
                    }
                } catch (Exception ignore) {
                    // 什么也不做...
                }
            }
            
            if (Objects.isNull(verticleCallable)) {
                throw new NoSuchBeanException("无法从对象工厂中装载 Verticle[" + verticleName + "] 对应的实例！");
            }
            
            promise.complete(verticleCallable);
        } catch (Exception e) {
            promise.fail(e);
        }
    }
    
}
